/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __ASTRO_TIMER_H__
#define __ASTRO_TIMER_H__

#include "Ogre.h"

namespace PQEngine
{
	class Astronomy
    {
	public:
		static const double PI;
		static const double J2000;/// January 1, 2000, noon

		static double radToDeg(double value);
		static double degToRad(double value);
		static double sinDeg(double x);
		static double cosDeg(double x);
		static double atan2Deg(double y, double x);
		static double normalizeDegrees(double value);
		static void convertEclipticToEquatorialRad(double lon, double lat,double &rasc, double &decl);
		static void convertRectangularToSpherical(double x, double y, double z,double &rasc, double &decl, double &dist);
		static void convertSphericalToRectangular(double rasc, double decl, double dist,double &x, double &y, double &z);
		static void convertEquatorialToHorizontal(double jday,double longitude,double latitude,double rasc,double decl,double &azimuth,double &altitude);

		/** Get astronomical julian day from normal gregorian calendar.
         *  From wikipedia: the integer number of days that have elapsed
         *  since the initial epoch defined as
         *  noon Universal Time(UT) Monday, January 1, 4713 BC
         *  @note this is the time at noon, not midnight.
         */
        static int getJulianDayFromGregorianDate(int year, int month, int day); 

		/** Get astronomical julian day from normal gregorian calendar.
         *  Calculate julian day from a day in the normal gregorian calendar.
         *  Time should be given as UTC.
         *  @see http://en.wikipedia.org/wiki/Julian_day
         */
        static double getJulianDayFromGregorianDateTime(int year, int month, int day,int hour, int minute, double second);

		/** Get the sun's position in the sky in, relative to the horizon.
         *  @param jday Astronomical time as julian day.
         *  @param longitude Observer longitude
         *  @param latitude Observer latitude
         *  @param azimuth Astronomical azimuth, measured clockwise from North = 0.
         *  @param altitude Astronomical altitude, elevation above the horizon.
         */
        static void getHorizontalSunPosition(double jday,double longitude, double latitude,double &azimuth, double &altitude);
        static void getHorizontalSunPosition(double jday,Ogre::Degree longitude, Ogre::Degree latitude,Ogre::Degree &azimuth, Ogre::Degree &altitude);

		/// Gets the moon position at a specific time in ecliptic coordinates
        /// @param lon: Ecliptic longitude, in radians.
        /// @param lat: Ecliptic latitude, in radians.
		static void getEclipticMoonPositionRad(double jday,double &lon,double &lat);

        static void getHorizontalMoonPosition(double jday,double longitude, double latitude,double &azimuth, double &altitude);
		static void getHorizontalMoonPosition(double jday,Ogre::Degree longitude, Ogre::Degree latitude,Ogre::Degree &azimuth, Ogre::Degree &altitude);

	};

	/*This class simulate the Astronomy time in used in universe(sun moon planets) simulation
	*/
	class AstroTimer
	{
	public:
        static const int SECONDS_PER_DAY=60*60*24;
	public:
		AstroTimer();
		void update(float deltaT);
		
		void setJulianDay(double value);
		void setTimeScale(float scale);
		void setGregorianDateTime(int year, int month, int day,int hour, int minute, double second);
		double getJulianDay() const;
		double getJulianDayDifference() const;
		double getJulianSecond() const;
		double getJulianSecondDifference() const;
		float getTimeScale() const;
	private:
		double _julianDayBase;/// Astronomical julian day at _currentTime = 0;
		double _currentTime;/// Seconds since _julianDayBase.
		double _lastUpdateTime;/// Seconds since _julianDayBase at last update.
		float _timeScale;/// Time scale.

	};

}
#endif
